package vipers

import (
	"bytes"
	"context"
	"io"
	"strings"
	"sync"
	"time"

	"github.com/spf13/viper"
	"go.etcd.io/etcd/client/v3"
)

type EtcdRemoteConfig struct {
	Mutex       sync.Mutex
	ClientCache map[string]*clientv3.Client
}

// 获取配置信息
func (c *EtcdRemoteConfig) Get(rp viper.RemoteProvider) (io.Reader, error) {
	client, err := c.newClient(rp)
	if err != nil {
		return nil, err
	}
	// 1秒超时
	ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
	resp, err := client.Get(ctx, rp.Path())
	cancel()

	if err != nil {
		return nil, err
	}

	return bytes.NewReader(resp.Kvs[0].Value), nil
}

// 监听配置信息
func (c *EtcdRemoteConfig) Watch(rp viper.RemoteProvider) (io.Reader, error) {
	client, err := c.newClient(rp)
	if err != nil {
		return nil, err
	}
	ch := client.Watch(context.Background(), rp.Path())
	res := <-ch
	return bytes.NewReader(res.Events[0].Kv.Value), nil
}

// 监听配置信息
func (c *EtcdRemoteConfig) WatchChannel(rp viper.RemoteProvider) (<-chan *viper.RemoteResponse, chan bool) {
	rr := make(chan *viper.RemoteResponse)
	stop := make(chan bool)
	go func() {
		client, err := c.newClient(rp)
		if err != nil {
			panic(err)
		}
		ch := client.Watch(context.Background(), rp.Path())
		for {
			select {
			case <-stop:
				return
			case res := <-ch:
				rr <- &viper.RemoteResponse{
					Value: res.Events[0].Kv.Value,
				}

			}
		}
	}()

	return rr, stop
}

// 新建etcd客户端
func (c *EtcdRemoteConfig) newClient(rp viper.RemoteProvider) (*clientv3.Client, error) {
	c.Mutex.Lock()
	defer c.Mutex.Unlock()
	if c.ClientCache == nil {
		c.ClientCache = make(map[string]*clientv3.Client, 0)
	}
	client := c.ClientCache[rp.Endpoint()]
	if client != nil {
		return client, nil
	}
	client, err := clientv3.New(clientv3.Config{
		Endpoints:   strings.Split(rp.Endpoint(), ","),
		DialTimeout: 2 * time.Second,
	})
	if err != nil {
		return nil, err
	}
	c.ClientCache[rp.Endpoint()] = client

	return client, nil
}
